﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UmlDesigner.Gui;
using UmlDesigner.Model.WorkUnits;

namespace UmlDesigner.Model
{
    class History
    {
        public UmlControl UmlControl
        {
            get;
            set;
        }

        public History()
        {
            undoRedoQueue = new LinkedList<IWorkUnit>();
            currentUndoRedoItem = null;
        }

        public void Add(IWorkUnit workUnit)
        {
            if (undoRedoQueue.Count != 0)
            {
                // Any items after the enumerator are pruned, and then the 
                // new one is added and the enumerator is adjusted
                if (currentUndoRedoItem == null)
                {
                    undoRedoQueue.Clear();
                }
                else
                {
                    currentUndoRedoItem = currentUndoRedoItem.Next;

                    while (currentUndoRedoItem != null)
                    {
                        LinkedListNode<IWorkUnit> tmp = currentUndoRedoItem;
                        currentUndoRedoItem = currentUndoRedoItem.Next;
                        undoRedoQueue.Remove(tmp);
                    }
                }
            }

            undoRedoQueue.AddLast(workUnit);
            currentUndoRedoItem = undoRedoQueue.Last;
            
            workUnit.Do(UmlControl);
        }

        public void Undo()
        {
            if (undoRedoQueue.Count > 0 && currentUndoRedoItem != null)
            {
                currentUndoRedoItem.Value.Undo(UmlControl);
                currentUndoRedoItem = currentUndoRedoItem.Previous;
                UmlControl.Invalidate();
            }
        }

        public void Redo()
        {
            if (undoRedoQueue.Count > 0)
            {
                if (currentUndoRedoItem == null)
                {
                    currentUndoRedoItem = undoRedoQueue.First;
                    currentUndoRedoItem.Value.Do(UmlControl);
                }
                else
                {
                    if (currentUndoRedoItem.Next != null)
                    {
                        currentUndoRedoItem = currentUndoRedoItem.Next;
                        currentUndoRedoItem.Value.Do(UmlControl);
                    }
                }
                UmlControl.Invalidate();
            }
        }

        private LinkedList<IWorkUnit> undoRedoQueue;
        private LinkedListNode<IWorkUnit> currentUndoRedoItem;
    }
}
